{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d006b2ea-9dfe-49c7-88a9-a5a0775185fd",
   "metadata": {},
   "source": [
    "# Additional End of week Exercise - week 2\n",
    "\n",
    "Now use everything you've learned from Week 2 to build a full prototype for the technical question/answerer you built in Week 1 Exercise.\n",
    "\n",
    "This should include a Gradio UI, streaming, use of the system prompt to add expertise, and the ability to switch between models. Bonus points if you can demonstrate use of a tool!\n",
    "\n",
    "If you feel bold, see if you can add audio input so you can talk to it, and have it respond with audio. ChatGPT or Claude can help you, or email me if you have questions.\n",
    "\n",
    "I will publish a full solution here soon - unless someone beats me to it...\n",
    "\n",
    "There are so many commercial applications for this, from a language tutor, to a company onboarding solution, to a companion AI to a course (like this one!) I can't wait to see your results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f41ef6c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "#impts\n",
    "import os\n",
    "import json\n",
    "import requests\n",
    "import gradio as gr\n",
    "from dotenv import load_dotenv\n",
    "from typing import List"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bdf94ce3",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Env set up\n",
    "\n",
    "load_dotenv()\n",
    "\n",
    "#local-i have ollama installed on my pc\n",
    "OLLAMA_URL = os.getenv(\"OLLAMA_BASE_URL\", \"http://localhost:11434/v1/completions\")\n",
    "OLLAMA_MODEL = os.getenv(\"LOCAL_MODEL_NAME\", \"llama3.2\")\n",
    "\n",
    "#cloude have anthropic api key\n",
    "ANTHROPIC_API_KEY = os.getenv(\"ANTHROPIC_API_KEY\")\n",
    "ANTHROPIC_MODEL = \"claude-sonnet-4-5-20250929\"  \n",
    "\n",
    "#system prompt\n",
    "SYSTEM_PROMPT = \"\"\"You are a helpful AI assistant with expertise in Python and software engineering.\n",
    "Explain code clearly and concisely. If asked about tools, respond only with accurate outputs.\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47353140",
   "metadata": {},
   "outputs": [],
   "source": [
    "#tool\n",
    "\n",
    "def get_ticket_price(city: str) -> dict:\n",
    "    prices = {\"Nairobi\": 120, \"Paris\": 800, \"Tokyo\": 950, \"New York\": 700}\n",
    "    return {\"destination\": city, \"price\": prices.get(city, \"unknown\")}\n",
    "\n",
    "\n",
    "def detect_and_run_tool(user_message: str):\n",
    "    if user_message.strip().startswith(\"/ticket\"):\n",
    "        parts = user_message.strip().split()\n",
    "        if len(parts) > 1:\n",
    "            city = parts[1]\n",
    "            return True, get_ticket_price(city)\n",
    "    return False, None\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d9496db",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Call fncs\n",
    "\n",
    "def ask_ollama(prompt: str) -> str:\n",
    "    try:\n",
    "        payload = {\"model\": OLLAMA_MODEL, \"prompt\": prompt, \"stream\": False}\n",
    "        r = requests.post(OLLAMA_URL, json=payload, timeout=120)\n",
    "        r.raise_for_status()\n",
    "        data = r.json()\n",
    "        return data.get(\"choices\", [{}])[0].get(\"text\", \"\").strip()\n",
    "    except Exception as e:\n",
    "        return f\"[Ollama error: {e}]\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ade4973",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "def ask_anthropic(prompt: str) -> str:\n",
    "    import anthropic\n",
    "    client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)\n",
    "    try:\n",
    "        response = client.messages.create(\n",
    "            model=ANTHROPIC_MODEL,\n",
    "            system=SYSTEM_PROMPT,\n",
    "            messages=[{\"role\": \"user\", \"content\": prompt}],\n",
    "            max_tokens=512,\n",
    "        )\n",
    "        return \"\".join(block.text for block in response.content if block.type == \"text\")\n",
    "    except Exception as e:\n",
    "        return f\"[Anthropic error: {e}]\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "760f6619",
   "metadata": {},
   "outputs": [],
   "source": [
    "#chat LOgic\n",
    "def chat_fn(user_message: str, history: List[List[str]], model_choice: str):\n",
    "    tool_used, tool_output = detect_and_run_tool(user_message)\n",
    "    if tool_used:\n",
    "        reply = f\"Tool executed. Result:\\n{json.dumps(tool_output, indent=2)}\"\n",
    "    else:\n",
    "        if model_choice == \"anthropic\":\n",
    "            reply = ask_anthropic(user_message)\n",
    "        else:\n",
    "            prompt = f\"{SYSTEM_PROMPT}\\n\\nUser: {user_message}\\nAssistant:\"\n",
    "            reply = ask_ollama(prompt)\n",
    "\n",
    "    history.append([user_message, reply])\n",
    "    return history"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11748f14",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Gradio UI\n",
    "def main():\n",
    "    with gr.Blocks(title=\"Week 2 QA Prototype\") as demo:\n",
    "        gr.Markdown(\"### Week 2 — Full Q/A Prototype\\nSupports Anthropic & Ollama models, plus a `/ticket <city>` tool.\")\n",
    "\n",
    "        # Message input comes first\n",
    "        msg = gr.Textbox(\n",
    "            placeholder=\"Ask your question or type /ticket Nairobi\",\n",
    "            label=\"Your message\",\n",
    "            lines=2,\n",
    "            autofocus=True\n",
    "        )\n",
    "\n",
    "        # Model selection and send button next\n",
    "        with gr.Row():\n",
    "            model_choice = gr.Radio([\"ollama\", \"anthropic\"], value=\"ollama\", label=\"Model\")\n",
    "            send = gr.Button(\"Send\", variant=\"primary\")\n",
    "\n",
    "        # Chatbot area\n",
    "        chatbot = gr.Chatbot(label=\"Conversation\", height=400)\n",
    "\n",
    "        # Wrapper \n",
    "        def wrapped_chat_fn(user_message, history, model_choice):\n",
    "            updated_history = chat_fn(user_message, history, model_choice)\n",
    "            return updated_history, gr.update(value=\"\")\n",
    "\n",
    "        # Send button and Enter key submission\n",
    "        send.click(wrapped_chat_fn, inputs=[msg, chatbot, model_choice], outputs=[chatbot, msg])\n",
    "        msg.submit(wrapped_chat_fn, inputs=[msg, chatbot, model_choice], outputs=[chatbot, msg])\n",
    "\n",
    "    demo.launch(server_name=\"0.0.0.0\", share=False)\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    main()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
